package cn.iocoder.yudao.module.trade.service.order;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.extra.spring.SpringUtil;
import cn.iocoder.yudao.framework.common.enums.UserTypeEnum;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.CheckUtils;
import cn.iocoder.yudao.framework.common.util.CollectionUtil;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
import cn.iocoder.yudao.module.member.api.user.MemberUserApi;
import cn.iocoder.yudao.module.member.api.user.UserRelationApi;
import cn.iocoder.yudao.module.member.api.user.dto.CrmMemberUserRespDTO;
import cn.iocoder.yudao.module.member.api.user.dto.MemberUserQueryRespDTO;
import cn.iocoder.yudao.module.member.api.user.dto.MemberUserRespDTO;
import cn.iocoder.yudao.module.member.api.user.dto.UserRelationDTO;
import cn.iocoder.yudao.module.pay.api.wallet.PayWalletApi;
import cn.iocoder.yudao.module.pay.api.wallet.dto.PayWalletDTO;
import cn.iocoder.yudao.module.product.api.crm.dto.CrmMemberInfoDto;
import cn.iocoder.yudao.module.product.api.enums.StockOwnerTypeEnum;
import cn.iocoder.yudao.module.product.api.spu.ProductSpuApi;
import cn.iocoder.yudao.module.product.api.spu.dto.ProductSpuRespDTO;
import cn.iocoder.yudao.module.product.api.stock.StockInfoApi;
import cn.iocoder.yudao.module.product.api.stock.dto.StockInfoDTO;
import cn.iocoder.yudao.module.trade.api.order.dto.TradeOrderPageDTO;
import cn.iocoder.yudao.module.trade.controller.admin.base.member.user.MemberUserRespVO;
import cn.iocoder.yudao.module.trade.controller.admin.order.vo.*;
import cn.iocoder.yudao.module.trade.controller.app.order.vo.AppTradeOrderPageReqVO;
import cn.iocoder.yudao.module.trade.dal.dataobject.delivery.DeliveryExpressDO;
import cn.iocoder.yudao.module.trade.dal.dataobject.depositorder.DepositOrderDO;
import cn.iocoder.yudao.module.trade.dal.dataobject.depositproductrelation.DepositProductRelationDO;
import cn.iocoder.yudao.module.trade.dal.dataobject.order.TradeOrderDO;
import cn.iocoder.yudao.module.trade.dal.dataobject.order.TradeOrderItemDO;
import cn.iocoder.yudao.module.trade.dal.mysql.order.TradeOrderItemMapper;
import cn.iocoder.yudao.module.trade.dal.mysql.order.TradeOrderMapper;
import cn.iocoder.yudao.module.trade.dal.redis.RedisKeyConstants;
import cn.iocoder.yudao.module.trade.enums.order.TradeOrderRefundStatusEnum;
import cn.iocoder.yudao.module.trade.enums.order.TradeOrderStatusEnum;
import cn.iocoder.yudao.module.trade.framework.delivery.core.client.ExpressClientFactory;
import cn.iocoder.yudao.module.trade.framework.delivery.core.client.dto.ExpressTrackQueryReqDTO;
import cn.iocoder.yudao.module.trade.framework.delivery.core.client.dto.ExpressTrackRespDTO;
import cn.iocoder.yudao.module.trade.service.delivery.DeliveryExpressService;
import cn.iocoder.yudao.module.trade.service.depositorder.DepositOrderService;
import cn.iocoder.yudao.module.trade.service.depositproductrelation.DepositProductRelationService;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.*;
import java.util.stream.Collectors;

import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet;
import static cn.iocoder.yudao.module.trade.enums.ErrorCodeConstants.EXPRESS_NOT_EXISTS;
import static cn.iocoder.yudao.module.trade.enums.ErrorCodeConstants.ORDER_NOT_FOUND;
import static java.util.Collections.singleton;

/**
 * 交易订单【读】 Service 实现类
 *
 * @author 芋道源码
 */
@Service
public class TradeOrderQueryServiceImpl implements TradeOrderQueryService {

    @Resource
    private ExpressClientFactory expressClientFactory;
    @Resource
    private TradeOrderMapper tradeOrderMapper;
    @Resource
    private TradeOrderItemMapper tradeOrderItemMapper;
    @Resource
    private DeliveryExpressService deliveryExpressService;
    @Resource
    @Lazy
    private MemberUserApi memberUserApi;
    @Resource
    private PayWalletApi payWalletApi;
    @Resource
    private StockInfoApi stockInfoApi;
    @Resource
    private UserRelationApi userRelationApi;

    @Resource
    private DepositOrderService depositOrderService;
    @Resource
    private DepositProductRelationService depositProductRelationService;
    @Resource
    private ProductSpuApi productSpuApi;

    @Override
    public MemberUserAddressRespVO getCrmMemberByVO(TradeOrderCreateRespVO tradeOrderCreateRespVO){
        MemberUserAddressRespVO memberUserRespVO = new MemberUserAddressRespVO();
        //查询燃气户
        List<CrmMemberUserRespDTO> memberUserRespDTOList = memberUserApi.getCrmMemberByMobile(BeanUtils.toBean(tradeOrderCreateRespVO, MemberUserQueryRespDTO.class));
        if(CollectionUtil.isEmpty(memberUserRespDTOList)){
            memberUserRespVO.setCrmMemberInfoVOList(new ArrayList<>());
            return memberUserRespVO;
        }
        List<CrmMemberInfoVO> resultList = new ArrayList<>();
        for(CrmMemberUserRespDTO crmMemberUserRespDTO : memberUserRespDTOList){
            //构建联系人户主账户相关信息
            CrmMemberInfoVO crmMemberInfoVO =  composeCrmMemberInfoDto(crmMemberUserRespDTO);
            if(CheckUtils.isEmpty(crmMemberInfoVO)){
                continue;
            }
            //查询上次订单记录
            LambdaQueryWrapperX<TradeOrderDO> queryWrapper = new LambdaQueryWrapperX<>();
            queryWrapper.eq(TradeOrderDO::getUserId,crmMemberInfoVO.getMemberUserId());
            queryWrapper.orderByDesc(TradeOrderDO::getId);
            queryWrapper.last("limit 1");
            TradeOrderDO tradeOrderDO = tradeOrderMapper.selectOne(queryWrapper);
            List<StockInfoDTO> stockInfoDOList = stockInfoApi.getStockList(crmMemberUserRespDTO.getId(), StockOwnerTypeEnum.CRM_MEMBER_TYPE.getCode());
            int stockCount = 0;
            if(!CollectionUtil.isEmpty(stockInfoDOList)){
                for(StockInfoDTO stockInfoDO : stockInfoDOList){
                    if(!CheckUtils.isEmpty(stockInfoDO)){
                        stockCount = stockCount + stockInfoDO.getSkuCount();
                    }
                }
            }
            //组装上次订单
            if(!CheckUtils.isEmpty(tradeOrderDO)){
                crmMemberInfoVO.setLastOrderTime(tradeOrderDO.getCreateTime());
                List<TradeOrderItemDO> orderItemDOS = getOrderItemListByOrderId(singleton(tradeOrderDO.getId()));
                List<TradeOrderItemBaseVO> tradeOrderItemBaseVOList = BeanUtils.toBean(orderItemDOS, TradeOrderItemBaseVO.class);
                for(TradeOrderItemBaseVO tradeOrderItemBaseVO : tradeOrderItemBaseVOList){
                    ProductSpuRespDTO productSpuRespDTO = productSpuApi.getSpu(tradeOrderItemBaseVO.getSpuId());
                    tradeOrderItemBaseVO.setCategoryId(productSpuRespDTO.getCategoryId());
                }
                crmMemberInfoVO.setTradeOrderItemBaseVOS(tradeOrderItemBaseVOList);
            }
            crmMemberInfoVO.setOwnCylinderCount(stockCount);
            crmMemberInfoVO.setMobile(crmMemberUserRespDTO.getMobile());
            crmMemberInfoVO.setPhone(crmMemberUserRespDTO.getPhone());
            crmMemberInfoVO.setStoreId(CheckUtils.isEmpty(crmMemberUserRespDTO.getNearbyStoreId()) ? null :         crmMemberUserRespDTO.getNearbyStoreId());
            crmMemberInfoVO.setStoreName(StrUtil.isEmpty(crmMemberUserRespDTO.getStoreName()) ? null : crmMemberUserRespDTO.getStoreName());
            crmMemberInfoVO.setLnglat(crmMemberUserRespDTO.getLnglat());
            resultList.add(crmMemberInfoVO);
        }
            memberUserRespVO.setCrmMemberInfoVOList(resultList);
            return memberUserRespVO;
    }

    private CrmMemberInfoVO composeCrmMemberInfoDto(CrmMemberUserRespDTO crmMemberUserDO){
        CrmMemberInfoDto crmMemberInfoDto = new CrmMemberInfoDto();
        crmMemberInfoDto.setId(crmMemberUserDO.getId());
        crmMemberInfoDto.setCrmName(crmMemberUserDO.getCrmName());
        crmMemberInfoDto.setCode(crmMemberUserDO.getCode());
        crmMemberInfoDto.setAddress(crmMemberUserDO.getDetailAddress());
        crmMemberInfoDto.setCreateTime(crmMemberUserDO.getCreateTime());
        crmMemberInfoDto.setAccountType(crmMemberUserDO.getAccountType());
        //获取户主信息
        UserRelationDTO userRelationDTO = userRelationApi.getUserRelationOne(crmMemberUserDO.getId());
        if(!CheckUtils.isEmpty(userRelationDTO)){
            Long memberUser = userRelationDTO.getMemberUserId();
            crmMemberInfoDto.setMemberUserId(memberUser);
            MemberUserRespDTO memberUserRespDTO = memberUserApi.getUser(memberUser);
            if(!CheckUtils.isEmpty(memberUserRespDTO)){
                crmMemberInfoDto.setTags(memberUserRespDTO.getTags());
                crmMemberInfoDto.setMemberLevel(memberUserRespDTO.getLevel());
                crmMemberInfoDto.setMemberCode(memberUserRespDTO.getId() + "");
                PayWalletDTO payWalletDTO = payWalletApi.getOrCreateWallet(userRelationDTO.getMemberUserId(), UserTypeEnum.MEMBER.getValue());
                crmMemberInfoDto.setBalance(payWalletDTO.getBalance());
                crmMemberInfoDto.setPoint(payWalletDTO.getPoint());
            }
            //押金信息获取
            List<DepositOrderDO> depositOrderDOS = depositOrderService.getDepositOrderList(crmMemberUserDO.getId());
            for(DepositOrderDO depositOrderDO : depositOrderDOS){
                if(CheckUtils.isEmpty(depositOrderDO)){
                    continue;
                }
                List<DepositProductRelationDO> depositProductRelationDOS = depositProductRelationService.getDepositProductRelationList(depositOrderDO.getId());
                Integer depositCylinderCount = 0;
                for(DepositProductRelationDO depositProductRelationDO : depositProductRelationDOS){
                    depositCylinderCount += depositProductRelationDO.getSkuCount();
                }
                crmMemberInfoDto.setDepositCylinderCount(depositCylinderCount);
            }
        }
        CrmMemberInfoVO crmMemberInfoVO = BeanUtils.toBean(crmMemberInfoDto,CrmMemberInfoVO.class);
        //联系人列表
        List<UserRelationDTO> userRelationDTOs = userRelationApi.getUserRelationList(crmMemberUserDO.getId());
        if(!CollectionUtil.isEmpty(userRelationDTOs)){
            List<Long> memberUserIds = userRelationDTOs.stream().map(UserRelationDTO::getMemberUserId).collect(Collectors.toList());
            List<MemberUserRespDTO> memberUserRespDTOList = memberUserApi.getUserList(memberUserIds);
            if(!CollectionUtil.isEmpty(memberUserRespDTOList)){
                List<MemberUserRespVO> memberUserRespVOS = BeanUtils.toBean(memberUserRespDTOList, MemberUserRespVO.class);
                memberUserRespVOS.forEach((e) ->{
                    if(Objects.equals(e.getMobile(),crmMemberUserDO.getPhone())){
                        e.setIsDefault(0);
                    }else{
                        e.setIsDefault(1);
                    }
                });
                memberUserRespVOS.sort(Comparator.comparingInt(MemberUserRespVO::getIsDefault));
                crmMemberInfoVO.setMemberUserRespVOS(memberUserRespVOS);
            }
        }
        return crmMemberInfoVO;
    }

    // =================== Order ===================

    @Override
    public TradeOrderDO getOrder(Long id) {
        return tradeOrderMapper.selectById(id);
    }

    @Override
    public TradeOrderDO getOrder(Long userId, Long id) {
        TradeOrderDO order = tradeOrderMapper.selectById(id);
        if (order != null
                && ObjectUtil.notEqual(order.getUserId(), userId)) {
            return null;
        }
        return order;
    }

    @Override
    public TradeOrderDO getOrderByUserIdAndStatusAndCombination(Long userId, Long combinationActivityId, Integer status) {
        return tradeOrderMapper.selectByUserIdAndCombinationActivityIdAndStatus(userId, combinationActivityId, status);
    }

    @Override
    public List<TradeOrderDO> getOrderList(Collection<Long> ids) {
        if (CollUtil.isEmpty(ids)) {
            return Collections.emptyList();
        }
        return tradeOrderMapper.selectBatchIds(ids);
    }

    @Override
    public PageResult<TradeOrderDO> getOrderPage(TradeOrderPageReqVO reqVO) {
        // 根据用户查询条件构建用户编号列表
        Set<Long> userIds = buildQueryConditionUserIds(reqVO);
        if (userIds == null) { // 没查询到用户，说明肯定也没他的订单
            return PageResult.empty();
        }
        // 分页查询
        return tradeOrderMapper.selectPage(reqVO, userIds);
    }

    private Set<Long> buildQueryConditionUserIds(TradeOrderPageReqVO reqVO) {
        // 获得 userId 相关的查询
        Set<Long> userIds = new HashSet<>();
        if (StrUtil.isNotEmpty(reqVO.getUserMobile())) {
            MemberUserRespDTO user = memberUserApi.getUserByMobile(reqVO.getUserMobile());
            if (user == null) { // 没查询到用户，说明肯定也没他的订单
                return null;
            }
            userIds.add(user.getId());
        }
        if (StrUtil.isNotEmpty(reqVO.getUserNickname())) {
            List<MemberUserRespDTO> users = memberUserApi.getUserListByNickname(reqVO.getUserNickname());
            if (CollUtil.isEmpty(users)) { // 没查询到用户，说明肯定也没他的订单
                return null;
            }
            userIds.addAll(convertSet(users, MemberUserRespDTO::getId));
        }
        return userIds;
    }

    @Override
    public TradeOrderSummaryRespVO getOrderSummary(TradeOrderPageReqVO reqVO) {
        // 根据用户查询条件构建用户编号列表
        Set<Long> userIds = buildQueryConditionUserIds(reqVO);
        if (userIds == null) { // 没查询到用户，说明肯定也没他的订单
            return new TradeOrderSummaryRespVO();
        }
        // 查询每个售后状态对应的数量、金额
        List<Map<String, Object>> list = tradeOrderMapper.selectOrderSummaryGroupByRefundStatus(reqVO, null);

        TradeOrderSummaryRespVO vo = new TradeOrderSummaryRespVO().setAfterSaleCount(0L).setAfterSalePrice(0L);
        for (Map<String, Object> map : list) {
            Long count = MapUtil.getLong(map, "count", 0L);
            Long price = MapUtil.getLong(map, "price", 0L);
            // 未退款的计入订单，部分退款、全部退款计入售后
            if (TradeOrderRefundStatusEnum.NONE.getStatus().equals(MapUtil.getInt(map, "refundStatus"))) {
                vo.setOrderCount(count).setOrderPayPrice(price);
            } else {
                vo.setAfterSaleCount(vo.getAfterSaleCount() + count).setAfterSalePrice(vo.getAfterSalePrice() + price);
            }
        }
        return vo;
    }

    @Override
    public PageResult<TradeOrderDO> getOrderPage(Long userId, AppTradeOrderPageReqVO reqVO) {
        return tradeOrderMapper.selectPage(reqVO, userId);
    }

    @Override
    public Long getOrderCount(Long userId, Integer status, Boolean commentStatus) {
        return tradeOrderMapper.selectCountByUserIdAndStatus(userId, status, commentStatus);
    }

    @Override
    public List<ExpressTrackRespDTO> getExpressTrackList(Long id, Long userId) {
        // 查询订单
        TradeOrderDO order = tradeOrderMapper.selectByIdAndUserId(id, userId);
        if (order == null) {
            throw exception(ORDER_NOT_FOUND);
        }
        // 查询物流
        return getExpressTrackList(order);
    }

    @Override
    public List<ExpressTrackRespDTO> getExpressTrackList(Long id) {
        // 查询订单
        TradeOrderDO order = tradeOrderMapper.selectById(id);
        if (order == null) {
            throw exception(ORDER_NOT_FOUND);
        }
        // 查询物流
        return getExpressTrackList(order);
    }

    @Override
    public int getSeckillProductCount(Long userId, Long activityId) {
        // 获得订单列表
        List<TradeOrderDO> orders = tradeOrderMapper.selectListByUserIdAndSeckillActivityId(userId, activityId);
        orders.removeIf(order -> TradeOrderStatusEnum.isCanceled(order.getStatus())); // 过滤掉【已取消】的订单
        if (CollUtil.isEmpty(orders)) {
            return 0;
        }
        // 获得订单项列表
        return tradeOrderItemMapper.selectProductSumByOrderId(convertSet(orders, TradeOrderDO::getId));
    }

    /**
     * 获得订单的物流轨迹
     *
     * @param order 订单
     * @return 物流轨迹
     */
    private List<ExpressTrackRespDTO> getExpressTrackList(TradeOrderDO order) {
        if (order.getLogisticsId() == null) {
            return Collections.emptyList();
        }
        // 查询物流公司
        DeliveryExpressDO express = deliveryExpressService.getDeliveryExpress(order.getLogisticsId());
        if (express == null) {
            throw exception(EXPRESS_NOT_EXISTS);
        }
        // 查询物流轨迹
        return getSelf().getExpressTrackList(express.getCode(), order.getLogisticsNo(), order.getReceiverMobile());
    }

    /**
     * 查询物流轨迹
     * 加个 spring 缓存，30 分钟；主要考虑及时性要求不高，但是每次调用需要钱；TODO @艿艿：这个时间不会搞了。。。交给你了哈哈哈
     *
     * @param code           快递公司编码
     * @param logisticsNo    发货快递单号
     * @param receiverMobile 收、寄件人的电话号码
     * @return 物流轨迹
     */
    @Cacheable(cacheNames = RedisKeyConstants.EXPRESS_TRACK, key = "#code + '-' + #logisticsNo + '-' + #receiverMobile",
            condition = "#result != null")
    public List<ExpressTrackRespDTO> getExpressTrackList(String code, String logisticsNo, String receiverMobile) {
        // 查询物流轨迹
        return expressClientFactory.getDefaultExpressClient().getExpressTrackList(
                new ExpressTrackQueryReqDTO().setExpressCode(code).setLogisticsNo(logisticsNo)
                        .setPhone(receiverMobile));
    }


    // =================== Order Item ===================

    @Override
    public TradeOrderItemDO getOrderItem(Long userId, Long itemId) {
        TradeOrderItemDO orderItem = tradeOrderItemMapper.selectById(itemId);
        if (orderItem != null
                && ObjectUtil.notEqual(orderItem.getUserId(), userId)) {
            return null;
        }
        return orderItem;
    }

    @Override
    public TradeOrderItemDO getOrderItem(Long id) {
        return tradeOrderItemMapper.selectById(id);
    }

    @Override
    public List<TradeOrderItemDO> getOrderItemListByOrderId(Collection<Long> orderIds) {
        if (CollUtil.isEmpty(orderIds)) {
            return Collections.emptyList();
        }
        return tradeOrderItemMapper.selectListByOrderId(orderIds);
    }

    /**
     * // 查询燃气户订单数量
     * @param id
     * @return
     */
    @Override
    public Integer getOrderCountByUserGasId(Long id) {
        LambdaQueryWrapperX<TradeOrderDO> orderDO = new LambdaQueryWrapperX<>();
        orderDO.eq(TradeOrderDO ::getMemberUserGasId, id);
        return tradeOrderMapper.selectCount(orderDO).intValue();
    }

    @Override
    public PageResult<TradeOrderPageDTO> getOrderListByUserGasId(TradeOrderPageDTO dto) {
        dto.setMemberUserGasId(dto.getId());
        PageResult<TradeOrderDO> page = tradeOrderMapper.selectPage(BeanUtils.toBean(dto,TradeOrderPageReqVO.class), new HashSet<>());
        PageResult<TradeOrderPageDTO> bean = BeanUtils.toBean(page, TradeOrderPageDTO.class);
        return bean;
    }

    /**
     * 获得自身的代理对象，解决 AOP 生效问题
     *
     * @return 自己
     */
    private TradeOrderQueryServiceImpl getSelf() {
        return SpringUtil.getBean(getClass());
    }

}
